package com.enation.app.javashop.core.goodssearch.service.impl;

import com.alibaba.fastjson.JSON;
import com.enation.app.javashop.core.base.CachePrefix;
import com.enation.app.javashop.core.base.rabbitmq.AmqpExchange;
import com.enation.app.javashop.core.client.goods.GoodsClient;
import com.enation.app.javashop.core.client.member.ShopCatClient;
import com.enation.app.javashop.core.goods.model.dto.BuyRecord;
import com.enation.app.javashop.core.goods.model.dto.TagsDTO;
import com.enation.app.javashop.core.goods.model.vo.GoodsSkuVO;
import com.enation.app.javashop.core.goods.service.TagsManager;
import com.enation.app.javashop.core.goodssearch.service.ShetuanSearchManager;
import com.enation.app.javashop.core.goodssearch.util.HexUtil;
import com.enation.app.javashop.core.goodssearch.util.SortContainer;
import com.enation.app.javashop.core.promotion.shetuan.model.dos.ShetuanGoodsGroupVO;
import com.enation.app.javashop.core.promotion.shetuan.model.dos.ShetuanGoodsSearchDTO;
import com.enation.app.javashop.core.promotion.shetuan.model.dos.ShetuanGoodsVO;
import com.enation.app.javashop.core.promotion.shetuan.model.dos.StGoodsDoc;
import com.enation.app.javashop.core.promotion.shetuan.model.enums.ShetuanGoodsStatusEnum;
import com.enation.app.javashop.core.promotion.shetuan.model.enums.ShetuanStatusEnum;
import com.enation.app.javashop.core.shop.model.dos.ShopCatDO;
import com.enation.app.javashop.core.shop.model.vo.ShopCatItem;
import com.enation.app.javashop.core.shop.service.ShopManager;
import com.enation.app.javashop.core.trade.cart.model.vo.CartSkuOriginVo;
import com.enation.app.javashop.core.trade.cart.service.CartOriginDataManager;
import com.enation.app.javashop.framework.cache.Cache;
import com.enation.app.javashop.framework.context.UserContext;
import com.enation.app.javashop.framework.database.DaoSupport;
import com.enation.app.javashop.framework.database.Page;
import com.enation.app.javashop.framework.elasticsearch.EsConfig;
import com.enation.app.javashop.framework.elasticsearch.EsSettings;
import com.enation.app.javashop.framework.exception.ServiceException;
import com.enation.app.javashop.framework.security.model.Buyer;
import com.enation.app.javashop.framework.util.BeanUtil;
import com.enation.app.javashop.framework.util.DateUtil;
import com.enation.app.javashop.framework.util.StringUtil;
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created by kingapex on 2019-01-21.
 * 拼团搜索业务实现者
 *
 * @author kingapex
 * @version 1.0
 * @since 7.1.0
 * 2019-01-21
 */

@Service
public class ShetuanSearchManagerImpl implements ShetuanSearchManager {


    @Autowired
    @Qualifier("tradeDaoSupport")
    private DaoSupport tradeDaoSupport;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Autowired
    private EsConfig esConfig;

    @Autowired
    private GoodsClient goodsClient;

    @Autowired
    private ShopManager shopManager;

    @Autowired
    private Cache cache;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ShopCatClient shopCatClient;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private TagsManager tagsManager;
    @Autowired
    private CartOriginDataManager cartOriginDataManager;

    protected final Log logger = LogFactory.getLog(this.getClass());

    public ShetuanSearchManagerImpl() {
    }

    @Override
    public boolean addIndex(ShetuanGoodsVO sheTuanGoodsVO, Map<String, Object> goods) {

        String goodsName = sheTuanGoodsVO.getGoodsName();
        long timestamp = DateUtil.getDateline();

        try {
            // 社区团购商品索引内容
            StGoodsDoc stGoodsDoc = new StGoodsDoc();
            BeanUtil.copyProperties(sheTuanGoodsVO,stGoodsDoc);

            stGoodsDoc.setTimestamp(timestamp);
            stGoodsDoc.setShetuanGoodsId(sheTuanGoodsVO.getId());
            stGoodsDoc.setGoodsName(goods.get("goods_name").toString());
            stGoodsDoc.setThumbnail(goods.get("thumbnail") == null ? "" : goods.get("thumbnail").toString());
            stGoodsDoc.setOriginal(goods.get("original") == null ? "" : goods.get("original").toString());
            stGoodsDoc.setVideoUrl(goods.get("video_url")==null ? "" : goods.get("video_url").toString() );
            stGoodsDoc.setSelling(goods.get("selling")==null ? "" : goods.get("selling").toString() );

            stGoodsDoc.setSellerId(StringUtil.toInt(goods.get("seller_id").toString(), 0));
            stGoodsDoc.setSellerName(goods.get("seller_name").toString()==null ? "" : goods.get("seller_name").toString());

            List<ShopCatItem> shopCatItems = goods.get("shop_cat_items") == null ? new ArrayList<>() : JSON.parseArray(goods.get("shop_cat_items").toString(), ShopCatItem.class);
            if(!CollectionUtils.isEmpty(shopCatItems)){
                List<String> pathList = shopCatItems.stream().map(ShopCatItem::getCatPath).collect(Collectors.toList());
                String concatRes = StringUtils.join(pathList, ",");
                stGoodsDoc.setShopCatPath(HexUtil.encode(concatRes));
            }


            stGoodsDoc.setDisabled(StringUtil.toInt(goods.get("disabled").toString(), 0));
            stGoodsDoc.setMarketEnable(StringUtil.toInt(goods.get("market_enable").toString(), 0));
            stGoodsDoc.setIsAuth(StringUtil.toInt(goods.get("is_auth").toString(), 0));
            stGoodsDoc.setIntro(goods.get("intro") == null ? "" : goods.get("intro").toString());
            stGoodsDoc.setEnableQuantity(Integer.valueOf(goods.get("enable_quantity").toString()));
            // 优先级
            stGoodsDoc.setPriority(sheTuanGoodsVO.getPriority() == null ? 50 : sheTuanGoodsVO.getPriority());
            // 商品评分
            stGoodsDoc.setGrade(Double.valueOf(goods.get("grade").toString()));
            stGoodsDoc.setSalesPrice(Double.valueOf(goods.get("price").toString()));
            // 购买数量
            stGoodsDoc.setBuyCount(StringUtil.toInt(goods.get("buy_count").toString(), 0));

            this.addIndex(stGoodsDoc);

            return true;
        } catch (Exception e) {
            logger.error("为社区团购商品[" + goodsName + "]生成索引报错", e);
            return false;
        }


    }

    private void addIndex(StGoodsDoc goodsDoc) {
        IndexQuery indexQuery = new IndexQuery();
        String indexName = esConfig.getIndexName() + "_" + EsSettings.SHETUAN_INDEX_NAME;
        indexQuery.setIndexName(indexName);
        indexQuery.setType(EsSettings.SHETUAN_TYPE_NAME);
        indexQuery.setId(goodsDoc.getShetuanId().toString() + goodsDoc.getSkuId().toString());
        indexQuery.setObject(goodsDoc);

        elasticsearchTemplate.index(indexQuery);

        logger.info("将社区团购商品ID[" + goodsDoc.getGoodsId() + "] " + goodsDoc + " 写入索引");
    }

    @Override
    public Page search(ShetuanGoodsSearchDTO goodsSearch) {

        Integer pageNo = goodsSearch.getPageNo()==null?1: goodsSearch.getPageNo();
        Integer pageSize = goodsSearch.getPageSize()==null?50: goodsSearch.getPageSize();

        SearchRequestBuilder searchRequestBuilder;
        try {
            //如果不为空 则表示关键词搜索
            if (!StringUtil.isEmpty(goodsSearch.getKeyword())) {
                //搜索关键字消息 热词统计
                this.amqpTemplate.convertAndSend(AmqpExchange.SEARCH_KEYWORDS, AmqpExchange.SEARCH_KEYWORDS + "_ROUTING", goodsSearch.getKeyword());
            }
            // 构建查询语句
            searchRequestBuilder = this.createQuery(goodsSearch);

            //设置分页信息
            searchRequestBuilder.setFrom((pageNo - 1) * pageSize).setSize(pageSize);

            // 设置是否按查询匹配度排序
            logger.debug("社区团购搜索：" + searchRequestBuilder);
            SearchResponse response = searchRequestBuilder.execute().actionGet();

            SearchHits searchHits = response.getHits();
            logger.info("社区团购搜索结果：" + JSON.toJSONString(searchHits));

            List<ShetuanGoodsVO> resultlist = new ArrayList<>();

            //查询购物车商品
            Map<Integer, Integer> cartNumMap = cartOriginDataManager.getUserCart();

            for (SearchHit hit : searchHits) {
                ShetuanGoodsVO shetuanGoodsVO = this.getShetuangoodsVO(hit);
                // 购物车社区团商品数量
                Integer cartNum = cartNumMap.get(shetuanGoodsVO.getSkuId());
                shetuanGoodsVO.setCartNum(cartNum == null ? 0 : cartNum);

                // 剩余库存
                GoodsSkuVO skuVO = goodsClient.getSkuFromCache(shetuanGoodsVO.getSkuId());

                // 累计已团
                String count = redisTemplate.opsForValue().get(CachePrefix.ST_BUY_NUM.getPrefix() + shetuanGoodsVO.getShetuanGoodsId());

                // 今日已团数量
                shetuanGoodsVO.calTodaySold(StringUtils.isEmpty(count) ? 0 : Integer.valueOf(count));

                Integer recordSize= shetuanGoodsVO.getTodaySoldQuantity()==null?0:shetuanGoodsVO.getTodaySoldQuantity();
                recordSize= recordSize>5?5:recordSize;
                List<BuyRecord> buyRecords =null;
                if(recordSize>0){
                    buyRecords = cache.range(CachePrefix.BUY_REC.getPrefix() + shetuanGoodsVO.getSkuId(), 0, recordSize-1);
                }
                shetuanGoodsVO.setBuyRecordList(buyRecords);

                // 库存数
                shetuanGoodsVO.calGoodsQuantity(skuVO);

                resultlist.add(shetuanGoodsVO);
            }

            List<ShetuanGoodsVO> newResultlist = resultlist;
            if (StringUtils.isEmpty(goodsSearch.getGoodsIds())) {
                newResultlist = new ArrayList<>();
                if (!CollectionUtils.isEmpty(resultlist)) {
                    Map<Integer, Integer> goodsIdAndSellerId = resultlist.stream().collect(Collectors.toMap(ShetuanGoodsVO::getGoodsId, ShetuanGoodsVO::getSellerId, (key1, key2) -> key2));
                    Map<Integer, List<TagsDTO>> allGoodsTags = this.tagsManager.getAllGoodsTags(goodsIdAndSellerId);
                    if (allGoodsTags != null) {
                        for (ShetuanGoodsVO goods : resultlist) {
                            List<TagsDTO> tagsDTOList = allGoodsTags.get(goods.getGoodsId());
                            if (!CollectionUtils.isEmpty(tagsDTOList)) {
                                goods.setGoodsListTags(this.tagsManager.tagsFilterAndComp("goodsListTags", tagsDTOList));
                            }
                            newResultlist.add(goods);
                        }
                    }
                }
            }

            Page webPage = new Page<>(pageNo, searchHits.getTotalHits(), pageSize, newResultlist);

            return webPage;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return new Page(pageNo, 0L, pageSize, new ArrayList());
    }

    public ShetuanSearchManagerImpl(ElasticsearchTemplate _elasticsearchTemplate, EsConfig _esConfig) {
        this.elasticsearchTemplate = _elasticsearchTemplate;
    }

    @Override
    public boolean delIndex(Integer shetuanId, Integer skuId) {
        String indexName = esConfig.getIndexName() + "_" + EsSettings.SHETUAN_INDEX_NAME;

        elasticsearchTemplate.delete(indexName, EsSettings.SHETUAN_TYPE_NAME, "" + shetuanId + skuId);

        if (logger.isDebugEnabled()) {
            logger.debug("将社区团购商品ID[" + shetuanId + "-" + skuId + "]删除索引");
        }
        return true;
    }

    @Override
    public boolean deleteByShetuanId(Integer shetuanId) {
        DeleteQuery dq = dq();

        dq.setQuery(QueryBuilders.termQuery("shetuanId", shetuanId));

        elasticsearchTemplate.delete(dq);
        return true;
    }

    @Override
    public List<ShetuanGoodsGroupVO> searchByShopCat(Integer shopCatId) {
        ShetuanGoodsSearchDTO shetuanGoodsSearchDTO = new ShetuanGoodsSearchDTO();
        shetuanGoodsSearchDTO.setShopCatId(shopCatId);
        // 耗资源
        Page search = this.search(shetuanGoodsSearchDTO);
        List<ShetuanGoodsVO> searchData = search.getData();
        Map<String, List<ShetuanGoodsVO>> shetuanGoodsGroupByShopCat = searchData.stream().collect(Collectors.groupingBy(ShetuanGoodsVO::getShopCatName, Collectors.toList()));
        List<ShetuanGoodsGroupVO> list = new ArrayList<>();
        for (Map.Entry<String, List<ShetuanGoodsVO>> entry : shetuanGoodsGroupByShopCat.entrySet()) {
            ShetuanGoodsGroupVO shetuanGoodsGroupVO = new ShetuanGoodsGroupVO();
            shetuanGoodsGroupVO.setShopCatName(entry.getKey());
            ShetuanGoodsVO shetuanGoodsVO = entry.getValue().get(0);
            shetuanGoodsGroupVO.setShopCatId(shetuanGoodsVO.getShopCatId());
            shetuanGoodsGroupVO.setShetuanGoodsList(entry.getValue());
            list.add(shetuanGoodsGroupVO);
        }
        return list;
    }

    private DeleteQuery dq() {
        DeleteQuery dq = new DeleteQuery();
        String indexName = esConfig.getIndexName() + "_" + EsSettings.SHETUAN_INDEX_NAME;
        dq.setIndex(indexName);
        dq.setType(EsSettings.SHETUAN_TYPE_NAME);
        return dq;
    }

    private SearchRequestBuilder createQuery(ShetuanGoodsSearchDTO goodsSearch) {
        // 关键字
        String keyword = goodsSearch.getKeyword();
        // 分类
        Integer shopCatId = goodsSearch.getShopCatId();
        // 商品IDS
        String goodsIds = goodsSearch.getGoodsIds();
        // 城市
            String city = goodsSearch.getCity();

        SearchRequestBuilder searchRequestBuilder = elasticsearchTemplate.getClient().prepareSearch(esConfig.getIndexName() + "_" + EsSettings.SHETUAN_INDEX_NAME);

        // 布尔查询构造器
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        // 关键字检索（商品名 规格名 类目名 ）
        if (!StringUtil.isEmpty(keyword)) {
             QueryStringQueryBuilder queryString = new QueryStringQueryBuilder(keyword).field("goodsName");
             boolQueryBuilder.must(queryString);

        }

        // 商品ids查询
        if (StringUtils.isNotEmpty(goodsIds)) {
            boolQueryBuilder.must(QueryBuilders.termsQuery("goodsId", goodsIds.split(",")));
        }

        if(StringUtils.isNotEmpty(city)){
            Integer shopId = shopManager.getShopByCity(city);
            boolQueryBuilder.must(QueryBuilders.termsQuery("sellerId",shopId.toString()));
        }

        // 商家分组搜索
        if (shopCatId != null) {
            ShopCatDO shopCat = shopCatClient.getModel(shopCatId);
            if (shopCat == null) {
                throw new ServiceException("5000", "该分组不存在");
            }
            boolQueryBuilder.must(QueryBuilders.wildcardQuery("shopCatPath", "*"+HexUtil.encode(shopCat.getCatPath()) + "*"));
        }

        // 状态 活动已上线  商品已上线
        boolQueryBuilder.must(QueryBuilders.termQuery("shetuanStatus", ShetuanStatusEnum.ON_LINE.getIndex()));
        boolQueryBuilder.must(QueryBuilders.termQuery("status", ShetuanGoodsStatusEnum.ON_LINE.getIndex()));

        searchRequestBuilder.setQuery(boolQueryBuilder);

        //排序
        String sortField = goodsSearch.getSort();

        if(!StringUtils.isEmpty(keyword) && StringUtils.isEmpty(sortField) ){
             return searchRequestBuilder;
        }

        String sortId = "priority";
        SortOrder sort = SortOrder.DESC;

        if (StringUtil.notEmpty(sortField)) {
            Map<String, String> sortMap = SortContainer.getSort(sortField);
            sortId = sortMap.get("id");
            // 如果是默认排序  --默认排序根据 商品优先级排序  add by liuyulei _2019-07-01
            if ("def".equals(sortId)) {
                sortId = "priority";
            }
            if ("buynum".equals(sortId)) {
                sortId = "buyCount";
            }
            if ("price".equals(sortId)) {
                sortId = "shetuanPrice";
            }

            if ("pick".equals(sortId)) {
                sortId = "pickTime";
            }

            if ("desc".equals(sortMap.get("def_sort"))) {
                sort = SortOrder.DESC;
            } else {
                sort = SortOrder.ASC;
            }
        }
        searchRequestBuilder.addSort(sortId, sort);


        //如果不是默认排序 则在原有搜索结果基础上加上商品优先级排序   add by liuyulei 2019-07-01
        if (!"priority".equals(sortId)) {
            //商品优先级
            searchRequestBuilder.addSort("priority", SortOrder.DESC);
        }
        return searchRequestBuilder;
    }


    /**
     * Es查询数据封装
     *
     * @param hit
     * @return
     */
    private ShetuanGoodsVO getShetuangoodsVO(SearchHit hit) {
        Map<String, Object> map = hit.getSourceAsMap();
        ShetuanGoodsVO shetuanGoodsVO = new ShetuanGoodsVO();
        shetuanGoodsVO.setShetuanGoodsId(map.get("shetuanGoodsId") == null ? null : Integer.valueOf(map.get("shetuanGoodsId").toString()));

        shetuanGoodsVO.setSkuId(Integer.valueOf(map.get("skuId").toString()));
        shetuanGoodsVO.setGoodsId(Integer.valueOf(map.get("goodsId").toString()));
        shetuanGoodsVO.setGoodsName(map.get("goodsName").toString());
        shetuanGoodsVO.setSelling(map.get("selling") == null ? "" : map.get("selling").toString());
        shetuanGoodsVO.setThumbnail(map.get("thumbnail").toString());
        shetuanGoodsVO.setVideoUrl(map.get("videoUrl") == null ? null : map.get("videoUrl").toString());
        shetuanGoodsVO.setOriginal(map.get("original") == null ? null : map.get("original").toString());

        shetuanGoodsVO.setShetuanPrice(Double.valueOf(map.get("shetuanPrice").toString()));
        // 市场价和店铺价取大值  最终值大于社区团购价
        shetuanGoodsVO.setSalesPrice(map.get("salesPrice") == null ? 0 : Double.valueOf(map.get("salesPrice").toString()));
        shetuanGoodsVO.setOriginPrice(map.get("originPrice") == null ? shetuanGoodsVO.getSalesPrice() : Double.valueOf(map.get("originPrice").toString()));
        shetuanGoodsVO.setGrade(map.get("grade") == null ? 100.00:Double.valueOf(map.get("grade").toString()));
        if (shetuanGoodsVO.getOriginPrice() <= shetuanGoodsVO.getShetuanPrice()) {
            shetuanGoodsVO.setOriginPrice(null);
        }
        shetuanGoodsVO.setEndTimeShow(DateUtil.toString(Long.valueOf(map.get("endTime").toString()), "MM月dd日"));
        shetuanGoodsVO.setPickTimeShow(DateUtil.toString(Long.valueOf(map.get("pickTime").toString()), "MM月dd日"));
        shetuanGoodsVO.setShopCatId(Integer.valueOf(map.get("shopCatId").toString()));
        shetuanGoodsVO.setShopCatName(map.get("shopCatName") == null ? "-" : map.get("shopCatName").toString());
        shetuanGoodsVO.setVisualNum(map.get("visualNum") == null ? 0 : Integer.valueOf(map.get("visualNum").toString()));
        shetuanGoodsVO.setEnableQuantity(Integer.valueOf(map.get("enableQuantity").toString()));
        shetuanGoodsVO.setGoodsNum(Integer.valueOf(map.get("goodsNum").toString()));
        shetuanGoodsVO.setShetuanId(Integer.valueOf(map.get("shetuanId").toString()));
        shetuanGoodsVO.setBuyNum(map.get("buyCount") == null ? 0 : Integer.valueOf(map.get("buyCount").toString()));
        shetuanGoodsVO.setLimitNum(map.get("limitNum") == null ? 0 : Integer.valueOf(map.get("limitNum").toString()));

        shetuanGoodsVO.setSellerId(map.get("sellerId") == null ? 0 : Integer.valueOf(map.get("sellerId").toString()));

        return shetuanGoodsVO;
    }
}
